#include <my_header.h>

typedef struct sharedArgs_s
{
    int clientfd;
}sharedArg;

typedef struct logicNode_s
{
    int fd;
    char* msg;
    int len;
}logicNode;


typedef struct ListNode_s
{
    logicNode* val;
    struct ListNode_s *next;
}ListNode;

typedef struct List_s
{
    ListNode* head;
    ListNode* tail;
    int size;
}List;

pthread_mutex_t usersM = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t fdsM = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t tdsM = PTHREAD_MUTEX_INITIALIZER;
int users = 0;
int fds[32];
int threads[32];
List* logicList = NULL;
pthread_mutex_t logicListM;
pthread_cond_t logicListC;


void lock(pthread_mutex_t* m){pthread_mutex_lock(m);}
void unlock(pthread_mutex_t* m){pthread_mutex_unlock(m);}
void cond_wait(pthread_cond_t* c,pthread_mutex_t* m){pthread_cond_wait(c,m);}
void cond_one(pthread_cond_t* c){pthread_cond_signal(c);}
void cond_all(pthread_cond_t* c){pthread_cond_broadcast(c);}

void creatrList()
{
    logicList = (List*)calloc(1,sizeof(List));
    logicList->head=NULL;
    logicList->tail=NULL;
    logicList->size=0;
    return ;
}

void freeList(List** list)
{
    ListNode* head = (*list)->head;
    ListNode* temp = NULL;
    while(head!=NULL)
    {
        temp = head->next;
        free(head->val->msg);
        free(head);
        head=temp;
    }
    free(*list);
    *list = NULL;
}

void pushNodeTail(logicNode* n)
{
    ListNode* node =(ListNode*)calloc(1,sizeof(ListNode));
    node->val = n;
    node->next = NULL;
    if(logicList->head==NULL)
    {
        logicList->head = node;
        logicList->tail = node;
    }
    else
    {
        logicList->tail->next = node;
        logicList->tail = node;
    }
    logicList->size++;
}

void popNodeHead()
{
    if(logicList->head == NULL)
    {
        return;
    }
    //logicNode* ret = logicList->head->val;
    if(logicList->head->next==NULL)
    {
        free(logicList->head->val->msg);
        free(logicList->head);
        logicList->head=NULL;
        logicList->tail=NULL;
    }
    else
    {
        ListNode* temp =logicList->head->next;
        free(logicList->head->val->msg);
        free(logicList->head);
        logicList->head = temp;
    }
    logicList->size--;
    //return ret;
}

void writeToQue(int fd,char* msg,int len)
{
    logicNode* node = (logicNode*)calloc(1,sizeof(logicNode));
    //printf("wt: %s\n",msg);
    node->fd = fd;
    node->msg = msg;
    node->len=len;
    lock(&logicListM);
    pushNodeTail(node);
    cond_one(&logicListC);
    unlock(&logicListM);
}

void* write_threadFunc(void* args)
{
    while(1)
    {
        lock(&logicListM);
        while(logicList->size==0)
        {
            cond_wait(&logicListC,&logicListM);
        }
        //send;
        logicNode* node = logicList->head->val;
        //printf("wt: %s\n",logicList->head->val->msg);
        for(int i=0;i<users;i++)
        {
            //printf("%d\n",fds[i]);
            if(fds[i]==node->fd){continue;}
            write(fds[i],node->msg,node->len);
        }
        popNodeHead();
        unlock(&logicListM);
        usleep(200);
    }

}


void* client_threadFunc(void* args)
{
    sharedArg* res= (sharedArg*)args;
    int clientfd= res->clientfd;
    char* buf = (char*)calloc(1024,1);
    while(1)
    {
        memset(buf,0,1024);
        //sleep(1);
        int ret = read(clientfd,buf,1024);
        if(ret==0)
        {
            printf("client closed!\n");
            break;
        }
        printf("client: %s\n",buf);
        //sleep(1);
        writeToQue(clientfd,buf,strlen(buf));
        usleep(200);
    }

    close(clientfd);
    return 0;
}


int main(int argc, char *argv[])
{
    int socfd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(12345);
    addr.sin_addr.s_addr = inet_addr("192.168.8.96");

    int ret = bind(socfd, (struct sockaddr*)&addr,sizeof(addr));
    ERROR_CHECK(ret,-1,"bind");

    listen(socfd,100);

    //pthread_t* threads = (pthread_t*)calloc(32,sizeof(pthread_t));
    creatrList();

    pthread_t writethread;
    pthread_create(&writethread,NULL,write_threadFunc,NULL);


    while(1)
    {
        struct sockaddr_in client_addr;
        socklen_t client_addr_len = sizeof(client_addr);
        int clientfd = accept(socfd,(struct sockaddr*)&client_addr,&client_addr_len);
        lock(&fdsM);
        fds[users]=clientfd;
        unlock(&fdsM);
        lock(&usersM);
        pthread_t t;
        threads[users] = t;
        users++;
        unlock(&usersM);
        sharedArg res;
        res.clientfd = clientfd;
        printf("----------\n");
        printf("%d %d\n",users,fds[users-1]);
        printf("----------\n");
        pthread_create(&t,NULL,client_threadFunc,(void*)&res);
    }    
    return 0;
}
